﻿
using System;
using System.Collections.Generic;
using System.Linq;
using Foothill.Common;
using Foothill.DataAccess;
using Foothill.DataAccess.Interface;
using Foothill.Model;
using Foothill.Service.Caching;
using Foothill.Service.MiscInfo;

namespace Foothill.Service.AdService
{
    using Exceptions;
    
    public class AdSearchService : IAdSearchService
    {
        private readonly IAdSearchRepo _adSearchRepo;
        private readonly ILocalCache _localCache;
        private readonly ISearchResultStatsCalculator _searchResultStatsCalculator;
        private readonly IAdListFilter _adListFilter;
        private readonly IMiscInfoService _miscInfoService;

        public AdSearchService(IAdSearchRepo adSearchRepo, ILocalCache localCache, IAdListFilter adListFilter,
            ISearchResultStatsCalculator statsCalculator, IMiscInfoService miscInfoService)
        {
            _adSearchRepo = adSearchRepo;
            _localCache = localCache;
            _adListFilter = adListFilter;
            _searchResultStatsCalculator = statsCalculator;
            _miscInfoService = miscInfoService;
        }

        public AdvancedSearchResult AdvancedSearch(ForSaleAdAdvancedSearchParameter searchParam)
        {
            AdvancedSearchResult searchResult = new AdvancedSearchResult();
            
            try
            {
                IList<ForSaleAd> resultSet = _adSearchRepo.AdvancedSearchGetAllResult(searchParam);

                searchResult.TotalNumberOfPost = resultSet.Count;
                searchResult.CompleteResultList = resultSet;
                    
                searchResult.MakeStatsList = _searchResultStatsCalculator.GetMakeStatsList(resultSet);
                searchResult.CityStatsList = _searchResultStatsCalculator.GetCityStatsList(resultSet);
                searchResult.ConditionStatsList = _searchResultStatsCalculator.GetConditionStatsList(resultSet);
                searchResult.ListingTypeStatsList = _searchResultStatsCalculator.GetListingTypeStatsList(resultSet);
                searchResult.TransmissionTypeStatsList = _searchResultStatsCalculator.GetTransmissionTypeStatsList(resultSet);

                IList<StatsItem> tmpStatsList1;
                IList<StatsItem> tmpStatsList2;

                _searchResultStatsCalculator.GetMileageStatsList(resultSet, out tmpStatsList1, out tmpStatsList2);
                searchResult.MileageStatsList = tmpStatsList1;
                searchResult.YearAgeStatsList = tmpStatsList2;
            }
            catch (DataAccessException exception)
            {
                throw new ServiceException("Data Access Error", exception);
            }

            return searchResult;
        }

        // construct search param for default list
        public ForSaleAdAdvancedSearchParameter ConstructDefaultSearchParameter()
        {
            ForSaleAdAdvancedSearchParameter result = new ForSaleAdAdvancedSearchParameter(_localCache.GetLocalApplicationDataDict(ApplicationDataNames.Cities).Keys.ToList());

            // indicate that it is a default search param
            result.IsDefault = true;

            // include all makes
            result.IncludeAllMakes = true;

            // year 
            result.AddRangeBasedAdSearchCriteria(RangeBasedCriteria.YearMade, GlobalSettings.StartYear, DateTime.Now.Year);

            // condition
            result.ConditionId = (int)VehicleCondition.Both;

            // with photo only
            result.WithPhotosOnly = true;

            // location list
            result.AllLocationSelected = true;

            // page size and page num
            result.PageNum = 1;
            result.PageSize = GlobalSettings.AdListPageSize;

            result.OrderByItem = OrderByItems.ByLastEditTime;
            result.SortDirection = fhSortDirection.DESC;

            result.FilterList = new List<AdCategorySelectItem>();

            return result;
        }

        public ForSaleAdAdvancedSearchParameter ConstructQuickSearchParameter(int makeId, int modelId, int maxMileage, PriceRange priceRangeFrom, PriceRange priceRangeTo)
        {
            ForSaleAdAdvancedSearchParameter result = new ForSaleAdAdvancedSearchParameter(_localCache.GetLocalApplicationDataDict(ApplicationDataNames.Cities).Keys.ToList());

            // make id and model Id
            result.IncludeAllMakes = false;
            result.AddMakeAndModel(makeId, modelId);

            // kilometers
            result.AddRangeBasedAdSearchCriteria(RangeBasedCriteria.Kilometer, 0, maxMileage);

            // price
            int priceFrom, priceTo;
            _miscInfoService.ConvertPriceEnumsToRange(priceRangeFrom, priceRangeTo, out priceFrom, out priceTo);

            if (priceTo != 0)
            {
                result.AddRangeBasedAdSearchCriteria(RangeBasedCriteria.Price, priceFrom, priceTo);
            }

            // condition
            result.ConditionId = (int)VehicleCondition.Both;

            // with photo only
            result.WithPhotosOnly = true;

            // location list
            result.AllLocationSelected = true;

            // page size and page num
            result.PageNum = 1;
            result.PageSize = GlobalSettings.AdListPageSize;

            result.OrderByItem = OrderByItems.ByLastEditTime;
            result.SortDirection = fhSortDirection.DESC;

            result.FilterList = new List<AdCategorySelectItem>();

            return result;
        }

        public void AssignMakeAndModelIds(ForSaleAdAdvancedSearchParameter searchParam,
            int makeId, int modelId, int makeId1, int modelId1, int makeId2, int modelId2)
        {
            searchParam.SelectedMakeAndModelIdLookup.Clear();
            
            if (makeId == GlobalValues.AllMakeId)
            {
                searchParam.IncludeAllMakes = true;
            }
            else
            {
                searchParam.IncludeAllMakes = false;

                searchParam.AddMakeAndModel(makeId, modelId);

                // add the 2nd and 3rd item
                AddMoreMakeAndModelId(searchParam, makeId1, modelId1);
                AddMoreMakeAndModelId(searchParam, makeId2, modelId2);
            }
        }

        public IList<ForSaleAd> FilterSearchResultList(ForSaleAdAdvancedSearchParameter searchParam, IList<ForSaleAd> completeResultList)
        {
            return _adListFilter.FilterSearchResultList(searchParam, completeResultList);
        }

        public IList<ForSaleAd> GetOnePage(IList<ForSaleAd> resultSet, int pageNum, int pageSize)
        {
            if (resultSet == null || resultSet.Count == 0)
            {
                return resultSet;
            }

            return resultSet.Skip((pageNum - 1) * pageSize).Take(pageSize).ToList();
        }
        
        internal void AddMoreMakeAndModelId(ForSaleAdAdvancedSearchParameter searchParam, int makeId, int modelId)
        {
            if (makeId == GlobalValues.IgnoreSelectedItemId)
            {
                return;
            }
            
            MakeAndModelSelection itemWithSameMakeId = searchParam.SelectedMakeAndModelIdLookup.FirstOrDefault(i => i.MakeId == makeId);
            if (itemWithSameMakeId != null)
            {
                if (itemWithSameMakeId.ModelId == GlobalValues.AllModelId || modelId == itemWithSameMakeId.ModelId)
                {
                    return;
                }
                else
                {
                    if (modelId == GlobalValues.AllModelId)
                    {
                        searchParam.SelectedMakeAndModelIdLookup.Remove(itemWithSameMakeId);
                    }
                    
                    searchParam.AddMakeAndModel(makeId, modelId);
                }
            }
            else
            {
                // no existing makeId, just add
                searchParam.AddMakeAndModel(makeId, modelId);
            }
        }
    }
}
